/* bzflag
 * Copyright (c) 1993-2020 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* OpenGLTexture:
 *  Encapsulates an OpenGL texture.
 *
 * Data must be in GL_RGBA format with type GL_UNSIGNED_BYTE.
 * If, for all pixels, the RGB components are equal, then
 * the data will be transformed to GL_LUMINANCE_ALPHA.  If,
 * for all pixels, the alpha component is opaque, then the
 * data will be transformed to GL_LUMINANCE or GL_RGB.
 * hasAlpha() will return true iff the alpha component was
 * kept.
 *
 * OpenGLTexture reference counts so copying or assigning a
 * texture keeps the same display list until the object is
 * changed.
 *
 * A default constructed texture is invalid.  The only way to
 * make such an object valid is to assign a valid texture to it.
 * Drawing an invalid texture has no effect.
 *
 * operator==() returns true iff the two objects refer to the
 * same display list.  operator!=() returns true iff the two
 * objects do not refer to the same display list.  Textures
 * that don't refer to the same display list but have exactly
 * the same texture map compare not-equal.
 *
 * <, <=, >, >= define an arbitrary ordering of textures.
 */

#ifndef BZF_OPENGL_TEXTURE_H
#define BZF_OPENGL_TEXTURE_H

#include "common.h"
#include <string>
#include "bzfgl.h"

class OpenGLTexture
{
public:
    enum Filter
    {
        Off,
        Nearest,
        Linear,
        NearestMipmapNearest,
        LinearMipmapNearest,
        NearestMipmapLinear,
        LinearMipmapLinear,
        Max = LinearMipmapLinear,
        Default = Max
    };

    OpenGLTexture(int width, int height,
                  const GLvoid* pixels,
                  Filter maxFilter = Linear,
                  bool repeat = true);
    ~OpenGLTexture();
    bool        hasAlpha() const;

    void        execute();

    float       getAspectRatio() const;
    int         getWidth() const;
    int         getHeight() const;

    bool        getPixelValue(int x, int y, unsigned char pixel[4]);

    Filter      getFilter();
    void        setFilter(Filter);

    void        freeContext();
    void        initContext();


    static int      getFilterCount();
    static const char*  getFilterName(Filter id);
    static const char** getFilterNames();

    static Filter   getMaxFilter();
    static void     setMaxFilter(Filter);

private:
    OpenGLTexture(const OpenGLTexture&);
    OpenGLTexture&  operator=(const OpenGLTexture&);

    bool        operator==(const OpenGLTexture&) const;
    bool        operator!=(const OpenGLTexture&) const;
    bool        operator<(const OpenGLTexture&) const;
    void        getBestFormat();
    void        bind();
    void        setupImage(const GLubyte* pixels);

    void* operator new(size_t s)
    {
        return ::operator new(s);
    }
    void  operator delete(void *p)
    {
        ::operator delete(p);
    }

    bool        alpha;
    const int       width;
    const int       height;
    GLubyte*        image;
    GLubyte*        imageMemory;
    bool        repeat;
    int         internalFormat;
    GLuint      list;
    Filter      filter;

    static Filter   maxFilter;

    static const int    filterCount;
    static const char*  configFilterNames[];

    static const GLenum minifyFilter[];
    static const GLenum magnifyFilter[];

    static void     static_freeContext(void *that);
    static void     static_initContext(void *that);

    friend class TextureManager;
};

//
// OpenGLTexture
//

inline bool     OpenGLTexture::hasAlpha() const
{
    return alpha;
}

inline int      OpenGLTexture::getWidth() const
{
    return width;
}
inline int      OpenGLTexture::getHeight() const
{
    return height;
}

#endif // BZF_OPENGL_TEXTURE_H

// Local Variables: ***
// mode: C++ ***
// tab-width: 4 ***
// c-basic-offset: 4 ***
// indent-tabs-mode: nil ***
// End: ***
// ex: shiftwidth=4 tabstop=4
